﻿using System;
using System.Linq.Expressions;
using System.Threading.Tasks;
using AnimationPage.Extensions;
using Avalonia.Controls;
using CommunityToolkit.Mvvm.ComponentModel;

namespace AnimationPage.ViewModels;

public partial class ViewModelBase : ObservableObject
{
    public static UserControl? Page;
    [ObservableProperty] private UserControl? _currentPage;

    [ObservableProperty] private bool _isBusy;

    protected object PropertyValueCheckLock = new();


    /// <summary>
    /// Runs a command if the updating flag is not set.
    /// If the flag is true (indicating the function is already running) then the action is not run.
    /// If the flag is false (indicating no running function) then the action is run.
    /// Once the action is finished if it was run, then the flag is reset to false
    /// </summary>
    /// <param name="updatingFlag">The boolean property flag defining if the command is already running</param>
    /// <param name="action">The action to run if the command is not already running</param>
    /// <returns></returns>
    protected async Task RunCommandAsync(Expression<Func<bool>> updatingFlag, Func<Task> action)
    {
        // Lock to ensure single access to check
        lock (PropertyValueCheckLock)
        {
            // Check if the flag property is true (meaning the function is already running)
            if (updatingFlag.GetPropertyValue())
                return;

            // Set the property flag to true to indicate we are running
            updatingFlag.SetPropertyValue(true);
        }

        try
        {
            // Run the passed in action
            await action();
        }
        finally
        {
            // Set the property flag back to false now it's finished
            updatingFlag.SetPropertyValue(false);
        }
    }

    /// <summary>
    /// Runs a command if the updating flag is not set.
    /// If the flag is true (indicating the function is already running) then the action is not run.
    /// If the flag is false (indicating no running function) then the action is run.
    /// Once the action is finished if it was run, then the flag is reset to false
    /// </summary>
    /// <param name="updatingFlag">The boolean property flag defining if the command is already running</param>
    /// <param name="action">The action to run if the command is not already running</param>
    /// <typeparam name="T">The type the action returns</typeparam>
    /// <returns></returns>
    protected async Task<T> RunCommandAsync<T>(Expression<Func<bool>> updatingFlag, Func<Task<T>> action,
        T defaultValue = default(T))
    {
        // Lock to ensure single access to check
        lock (PropertyValueCheckLock)
        {
            // Check if the flag property is true (meaning the function is already running)
            if (updatingFlag.GetPropertyValue())
                return defaultValue;

            // Set the property flag to true to indicate we are running
            updatingFlag.SetPropertyValue(true);
        }

        try
        {
            // Run the passed in action
            return await action();
        }
        finally
        {
            // Set the property flag back to false now it's finished
            updatingFlag.SetPropertyValue(false);
        }
    }


    // protected async Task RunCommandAsync(Func<Task> action)
    // {
    //     lock (PropertyValueCheckLock)
    //     {
    //         if (IsBusy)
    //             return;
    //
    //         IsBusy = true;
    //     }
    //
    //     try
    //     {
    //         await action();
    //     }
    //     finally
    //     {
    //         IsBusy = false;
    //     }
    // }
}